跳到主要内容

对象的属性劫持

本节你将学习到如何利用 JavaScriptObject.defineProperty 进行对象属性的劫持。

语法

Object.defineProperty使用在一个对象上,可以新增一个属性或修改一个现有的属性。

其语法为

Object.defineProperty(obj, prop, descriptor);

参数

参数描述
obj我们要操纵的对象
prop要操纵对象上的哪个属性值
descriptor

属性描述符,描述该属性被读取或写入时应表现的行为,分为 数据描述符存取描述符 两种。

  • 数据描述符更倾向于结果
  • 存取描述符更倾向于过程。
提示

比如当我们想要读取 obj.name,如果通过数据描述符设置,应该设置这个值是什么,而存取描述符则是设置读写的时候所触发的函数。

数据描述符存取描述符 都分别有各自的设置键值,但是也有共有的键值,我们先看共有的键值,有 configurable 以及 enumerable

共有键值

键值说明
configurable默认为 false,即除了 value 以及 writable 之外的其他属性都不能被修改。只有为 true 的时候,该属性的描述符才能被改变。
另外,writable 只能从 true 改为 false,不能从 false 改为 true
enumerable默认为 false,只有为 true 的时候才出现在对象的枚举属性中,枚举指 Object.keys 等获取对象所有属性的 API
注意

当对象中不存在属性的时候,会直接根据描述符默认值进行赋值,但当对象已经存在该属性,并且描述符的属性未显式声明的时候,会以已存在的属性为准,下同。

数据描述符专有属性

数据描述符有两个属性,valuewritable

属性说明
value当读取该属性的时候,所返回的属性对应的值,可以是任何 JavaScript 有效的值,
如数值,对象,函数等。
writable是否可写,即 value 是否能被 赋值运算符(=) 等改变,默认为 false

存取描述符专有属性

存取描述符有两个属性,getset

属性说明
get当访问该属性时,会调用此函数。
执行时不传入任何参数,但是会传入 this 对象
(由于继承关系,这里的 this 并不一定是定义该属性的对象)。
该函数的返回值会被用作属性的值。
set当属性值被修改时,会调用此函数。
该方法接受一个参数(也就是被赋予的新值),
会传入赋值时的 this 对象。

使用

具体怎么用我们可以看一些小栗子,这个函数相当于在访问对象内的属性的时候进行了一层过滤,可以篡改读取到的数据以及设置的数据

可以看一下 MDN 官方的例子有一个非常好的体现

//创建一个object1
const object1 = {};
// 设置object1的属性property1,值为42,不可写
Object.defineProperty(object1, "property1", {
value: 42,
writable: false,
});
// 再设置object1的property1属性为77,但是会爆出一个错误
object1.property1 = 77; // 严格模式下会爆出错误
//访问property,结果为42
console.log(object1.property1); // 期望输出: 42

不仅仅可以设置为对象,也可以设置 setget 来控制读取和写入

Object.defineProperty(obj, "attr", {
get: function () {
//获取的数据;
},
set: function (str) {
//设置的数据;
},
});